package com.waypolice.manager.component;

import com.waypolice.common.constant.CmsResult;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.delegate.Expression;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.task.TaskDefinition;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.MalformedParameterizedTypeException;
import java.util.*;

/**
 * 描述:
 *
 * @author zyp
 * @description 工作流指定下一个审批人
 * @create 2019-03-15 10:10
 */
@Component
public class ActivitiAppointTask{

    private static final Logger logger = LoggerFactory.getLogger(ActivitiEndExectuionListener.class);

    @Autowired
    protected RuntimeService runtimeService;

    @Autowired
    protected TaskService taskService;

    @Autowired
    protected RepositoryService repositoryService;
    
    /**
     * @author:zyp
     * @description 指定下一个审批人
     * @date: 2019/3/15 11:33
     * @return 
     */
    public Object appointTask(String taskId){
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        ProcessDefinitionEntity processDefinitionEntity = null;
        String id = null;
        TaskDefinition taskDefinition= null;
        //当前流程节点Id信息
        String activitiId = task.getTaskDefinitionKey();
        String definitionId = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult().getProcessDefinitionId();
        processDefinitionEntity = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(definitionId);
        //获取流程所有节点信息  
        List<ActivityImpl> activitiList = processDefinitionEntity.getActivities();
        //循环遍历 获取当前节点联系的下一个节点的名称和信息
        Map<String,String> pointMap = new HashMap<>();
        for(ActivityImpl activityImpl : activitiList){
            id = activityImpl.getId();
            //当查到的是当前的节点是，查找下一个连线的节点
            if (activitiId.equals(id)) {
                pointMap = getNextPoint(activityImpl, activitiId);
                break;
            }
        }
        //再次遍历 获取下一个的节点信息
        for(ActivityImpl activityImpl : activitiList){
            id = activityImpl.getId();
            //当id与下一个节点信息相同时
            if (id.equals(pointMap.get("pointName"))) {
                taskDefinition = nextTaskDefinition(activityImpl, activitiId);
                break;
            }
        }
        //当前工作流不指向修改调整
        if(taskDefinition!=null&&taskDefinition.getAssigneeExpression()!=null&&!"modifyApply".equals(taskDefinition.getKey())){
            //执行的内容
            String assignee = taskDefinition.getAssigneeExpression().getExpressionText();
            //是否为指定下一个审批人
            boolean isAppoint;
            if(StringUtils.isNotBlank(assignee)){
                isAppoint = assignee.contains("${");
                //如果是指定
                if(isAppoint){
                    String taskUser = assignee.replaceAll("[${}]","");
                    return new CmsResult(1,taskUser,null);
                }
            }
            return new CmsResult(0,null,null);
        }else{
            return new CmsResult(0,null,null);
        }
    }

    /**
     * @author:zyp
     * @description 获取第一个审批节点 从而判断是否需要制定审批人
     * @date: 2019/3/27 17:13
     * @return 
     */
    public Object getFirstTaks(String key,String trem){
        //执行的内容
        String assignee = getNodeInfo(key,trem);
        //是否为指定下一个审批人
        boolean isAppoint;
        if(StringUtils.isNotBlank(assignee)){
            isAppoint = assignee.contains("${");
            //如果是指定
            if(isAppoint){
                String taskUser = assignee.replaceAll("[${}]","");
                return new CmsResult(1,taskUser,null);
            }
        }else{
            return new CmsResult(0,null,null);
        }
        return new CmsResult(0,null,null);
    }

    /**
     * @author:zyp
     * @description 获取该节点的下一个节点或网关
     * @date: 2019/6/20 16:08
     * @return
     */
    private Map<String,String> getNextPoint(ActivityImpl activityImpl, String activityId){
        //保存当前节点的下一个节点的线路终点节点，终点节点的类型
        Map<String,String> map = new HashMap<>();
        // 获取节点所有流向线路信息
        List<PvmTransition> outTransitions = activityImpl.getOutgoingTransitions();
        String pointName = null;
        String type = null;
        // 获取线路的终点节点,目前从usertask出来的线路只有一条，故不做循环
        PvmActivity ac = outTransitions.get(0).getDestination();
        // 如果流向线路为排他网关
        if ("exclusiveGateway".equals(ac.getProperty("type"))) {
            pointName = ac.getId();
            type =  "exclusiveGateway";
        }else if("userTask".equals(ac.getProperty("type"))){
            pointName = ac.getId();
            type =  "userTask";
        }
        map.put("pointName",pointName);
        map.put("type",type);
        return map;
    }

    /**
     * @author:zyp
     * @description 下一个任务节点信息
     * @date: 2019/3/15 11:47
     * @return 
     */
    private TaskDefinition nextTaskDefinition(ActivityImpl activityImpl, String activityId){
        String type = (String) activityImpl.getProperty("type");
        // 如果遍历节点为用户任务并且节点不是当前节点信息
        if ("userTask".equals(type) && !activityId.equals(activityImpl.getId())) {
            // 获取该节点下一个节点信息
            if(activityImpl.getActivityBehavior() instanceof UserTaskActivityBehavior){
                UserTaskActivityBehavior aaBehavior =(UserTaskActivityBehavior)activityImpl.getActivityBehavior();
                return aaBehavior.getTaskDefinition();
            } else if(activityImpl.getActivityBehavior() instanceof ParallelMultiInstanceBehavior){
                ParallelMultiInstanceBehavior aaBehavior =(ParallelMultiInstanceBehavior)activityImpl.getActivityBehavior();
                return ((UserTaskActivityBehavior)aaBehavior.getInnerActivityBehavior()).getTaskDefinition();
            }
        }else if("exclusiveGateway".equals(activityImpl.getProperty("type"))){
            List<PvmTransition> outTransitions = activityImpl.getOutgoingTransitions();
            // 如果排他网关只有一条线路信息
            if (outTransitions.size() == 1) {
                return nextTaskDefinition((ActivityImpl) outTransitions.get(0).getDestination(), activityId);
                // 如果排他网关有多条线路信息
            } else if (outTransitions.size() > 1) {
                for (PvmTransition tr1 : outTransitions) {
                    // 查看当前的线路指向的节点是否为modifyApply，如果为 则选择另外一个节点
                    PvmActivity ac = tr1.getDestination();
                    String pointName = ac.getId();
                    if(pointName.contains("modifyApply")){
                        continue;
                    }
                    // 获取排他网关线路判断条件信息  //默认为通过，因为不通过都会返回到调整页面
                    return nextTaskDefinition((ActivityImpl) ac, activityId);
                }
            }
        }
        return null;
    }

    /**
     * @author:zyp
     * @description 根据唯一标识Key 获取部署后的定义对象，获取定义ID，通过定义ID获取模型 从而得到各节点,在根据当前节点查找下一个节点，
     * @date: 2019/3/27 16:50
     * @return
     */
    private String getNodeInfo(String key,String trem){
        List<ProcessDefinition> processDefinitionList = repositoryService.createProcessDefinitionQuery().processDefinitionKey(key).list();
        BpmnModel model = repositoryService.getBpmnModel(processDefinitionList.get(processDefinitionList.size()-1).getId());
        ProcessDefinitionEntity processDefinitionEntity = null;
        processDefinitionEntity = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(processDefinitionList.get(0).getId());
        //获取流程所有节点信息  
        List<ActivityImpl> activitiList = processDefinitionEntity.getActivities();
        //获取第一个节点名字
        String activitiId;
        //节点信息id
        String id;
        TaskDefinition taskDefinition= null;
        if(model != null) {
            //获取所有节点信息
            Collection<FlowElement> flowElements = model.getMainProcess().getFlowElements();
            //获取第一个开始时的节点信息
            FlowElement flowElement = (FlowElement) ((List)flowElements).get(0);
            activitiId = flowElement.getId();
            //循环遍历 获取当前节点联系的下一个节点的名称和信息
            Map<String,String> pointMap = new HashMap<>();
            //获取流程所有节点信息 
            for(ActivityImpl activityImpl : activitiList){
                id = activityImpl.getId();
                //当查到的是当前的节点是，查找下一个连线的节点
                if (activitiId.equals(id)) {
                    pointMap = getNextPoint(activityImpl, activitiId);
                    break;
                }
            }
            //再次遍历 获取下一个的节点信息
            for(ActivityImpl activityImpl : activitiList){
                id = activityImpl.getId();
                //当id与下一个节点信息相同时
                if (id.equals(pointMap.get("pointName"))) {
                    taskDefinition = nextTaskDefinitionByTerm(activityImpl, activitiId,trem);
                    break;
                }
            }
        }
        String assignee = "";
        if(taskDefinition!=null&&taskDefinition.getAssigneeExpression()!=null){
            //执行的内容
            assignee = taskDefinition.getAssigneeExpression().getExpressionText();
        }
        return assignee;
    }


    /**
     * @author:zyp
     * @description 下一个任务节点信息
     * @date: 2019/3/15 11:47
     * @return
     */
    private TaskDefinition nextTaskDefinitionByTerm(ActivityImpl activityImpl, String activityId,String trem){
        String type = (String) activityImpl.getProperty("type");
        // 如果遍历节点为用户任务并且节点不是当前节点信息
        if ("userTask".equals(type) && !activityId.equals(activityImpl.getId())) {
            // 获取该节点下一个节点信息
            if(activityImpl.getActivityBehavior() instanceof UserTaskActivityBehavior){
                UserTaskActivityBehavior aaBehavior =(UserTaskActivityBehavior)activityImpl.getActivityBehavior();
                return aaBehavior.getTaskDefinition();
            } else if(activityImpl.getActivityBehavior() instanceof ParallelMultiInstanceBehavior){
                ParallelMultiInstanceBehavior aaBehavior =(ParallelMultiInstanceBehavior)activityImpl.getActivityBehavior();
                return ((UserTaskActivityBehavior)aaBehavior.getInnerActivityBehavior()).getTaskDefinition();
            }
        }else if("exclusiveGateway".equals(activityImpl.getProperty("type"))){
            List<PvmTransition> outTransitions = activityImpl.getOutgoingTransitions();
            // 如果排他网关只有一条线路信息
            if (outTransitions.size() == 1) {
                return nextTaskDefinitionByTerm((ActivityImpl) outTransitions.get(0).getDestination(), activityId,trem);
                // 如果排他网关有多条线路信息
            } else if (outTransitions.size() > 1) {
                for (PvmTransition tr1 : outTransitions) {
                    // 查看当前的线路指向的节点是否为modifyApply，如果为 则选择另外一个节点
                    PvmActivity ac = tr1.getDestination();
                    Object conditionText = tr1.getProperty("conditionText");
                    if(((String)conditionText).contains(trem)){
                        // 获取排他网关线路判断条件信息  //默认为通过，因为不通过都会返回到调整页面
                        return nextTaskDefinitionByTerm((ActivityImpl) ac, activityId,trem);
                    }
                }
            }
        }
        return null;
    }
}